using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using FireStarter.Base;
using FireStarter.CodeGeneration;
using FireStarter.CodeGeneration.Generator;
using FireStarterModeller.BO;
using FireStarterModeller.Test;
using Habanero.BO;
using Habanero.BO.ClassDefinition;
using Habanero.BO.Loaders;
using NUnit.Framework;
using Rhino.Mocks;

namespace FireStarter.Test.CodeGeneration.Generator
{
    [TestFixture]
    public class TestReflectionGenerationStrategy
    {
        //TODO: Test case sensitivity. (done for value delegates dictionary)

        [TestFixtureSetUp]
        public void TestFixtureSetup()
        {
            ClassDef.ClassDefs.Add(new XmlClassDefsLoader(BOBroker.GetClassDefsXml(), new DtdLoader()).LoadClassDefs());
            BORegistry.DataAccessor = new DataAccessorInMemory();
        }

        [Test]
        public void TestGetValue_String()
        {
            //---------------Set up test pack-------------------
            IGenerationStrategy generationStrategy = new ReflectionGenerationStrategy();
            //---------------Assert Precondition----------------
            string randomString = TestUtilsCodeGen.GetRandomString();
            IModelElement modelElement = new MockModelElement(randomString);
            //---------------Execute Test ----------------------
            object value = generationStrategy.GetValue(null, modelElement, "Value");
            //---------------Test Result -----------------------
            Assert.AreEqual(randomString, value);
        }

        [Test]
        public void TestGetValue_Int()
        {
            //---------------Set up test pack-------------------
            IGenerationStrategy generationStrategy = new ReflectionGenerationStrategy();
            //---------------Assert Precondition----------------
            int randomInt = new Random().Next();
            IModelElement modelElement = new MockModelElement(randomInt);
            //---------------Execute Test ----------------------
            object value = generationStrategy.GetValue(null, modelElement, "Value");
            //---------------Test Result -----------------------
            Assert.AreEqual(randomInt, value);
        }

        [Test]
        public void TestGetValue_Null()
        {
            //---------------Set up test pack-------------------
            IGenerationStrategy generationStrategy = new ReflectionGenerationStrategy();
            //---------------Assert Precondition----------------
            IModelElement modelElement = new MockModelElement(null);
            //---------------Execute Test ----------------------
            object value = generationStrategy.GetValue(null, modelElement, "Value");
            //---------------Test Result -----------------------
            Assert.IsNull(value);
        }

        [Test]
        public void TestGetValue_NonExistantProperty()
        {
            //---------------Set up test pack-------------------
            IGenerationStrategy generationStrategy = new ReflectionGenerationStrategy();
            string propertyName = "NotExistingProp";
            //---------------Assert Precondition----------------
            IModelElement modelElement = new MockModelElement(null);
            //---------------Execute Test ----------------------
            try
            {
                generationStrategy.GetValue(null, modelElement, propertyName);
                Assert.Fail("Should have thrown an error");
                //---------------Test Result -----------------------
            }
            catch (PropertyMissingException ex)
            {
                StringAssert.Contains(propertyName, ex.PropertyName);
                StringAssert.Contains(string.Format("The property '{0}' does not exist on this IModelElement of type '{1}'.", propertyName, modelElement.GetType().FullName), ex.Message);
            }
        }

        [Test]
        public void TestGetValue_ParentProperty()
        {
            //---------------Set up test pack-------------------
            IGenerationStrategy generationStrategy = new ReflectionGenerationStrategy();
            string propertyName = "ParentProperty";
            //---------------Assert Precondition----------------
            MockModelElementParent modelElementParent = new MockModelElementParent();
            modelElementParent.ParentProperty = TestUtilsCodeGen.GetRandomString();
            MockModelElement modelElement = new MockModelElement(null);
            modelElement.Parent = modelElementParent;
            ModelStrategyMapper modelStrategyMapper = new ModelStrategyMapper();
            modelStrategyMapper.SetStrategy(typeof(IModelElement), generationStrategy);
            //---------------Execute Test ----------------------
            object value = generationStrategy.GetValue(modelStrategyMapper, modelElement, propertyName);
            //---------------Test Result -----------------------
            Assert.AreEqual(modelElementParent.ParentProperty, value);
        }

        [Test]
        public void TestGetValue_ParentProperty_DoesntExist()
        {
            //---------------Set up test pack-------------------
            IGenerationStrategy generationStrategy = new ReflectionGenerationStrategy();
            string propertyName = "NonExistingParentProperty";
            //---------------Assert Precondition----------------
            MockModelElementParent modelElementParent = new MockModelElementParent();
            modelElementParent.ParentProperty = TestUtilsCodeGen.GetRandomString();
            MockModelElement modelElement = new MockModelElement(null);
            modelElement.Parent = modelElementParent;
            ModelStrategyMapper modelStrategyMapper = new ModelStrategyMapper();
            modelStrategyMapper.SetStrategy(typeof(IModelElement), generationStrategy);
            //---------------Execute Test ----------------------
            try
            {
                generationStrategy.GetValue(modelStrategyMapper, modelElement, propertyName);
                Assert.Fail("Should have thrown an error");
                //---------------Test Result -----------------------
            }
            catch (PropertyMissingException ex)
            {
                StringAssert.Contains(propertyName, ex.PropertyName);
                StringAssert.Contains(string.Format("The property '{0}' does not exist on this IModelElement of type '{1}'.", propertyName, modelElement.GetType().FullName), ex.Message);
            }
        }

        [Test]
        public void TestGetValue_IsCaseInsensitive()
        {
            //---------------Set up test pack-------------------
            IGenerationStrategy generationStrategy = new ReflectionGenerationStrategy();
            //---------------Assert Precondition----------------
            string randomString = TestUtilsCodeGen.GetRandomString();
            IModelElement modelElement = new MockModelElement(randomString);
            //---------------Execute Test ----------------------
            object value = generationStrategy.GetValue(null, modelElement, "VALUE");
            //---------------Test Result -----------------------
            Assert.AreEqual(randomString, value);
        }

        [Test]
        public void TestGetValue_CamelCase()
        {
            //---------------Set up test pack-------------------
            //<<|=#Property|>>
            IGenerationStrategy generationStrategy = new ReflectionGenerationStrategy();
            //---------------Assert Precondition----------------
            string propertyName = "PropertyName";
            IModelElement modelElement = new MockModelElement(propertyName);
            //---------------Execute Test ----------------------
            object value = generationStrategy.GetValue(null, modelElement, "#Value");
            //---------------Test Result -----------------------
            Assert.AreEqual("propertyName", value);
        }

        [Test]
        public void TestGetValue_Plural()
        {
            //---------------Set up test pack-------------------
            //<<|=Property+|>>
            IGenerationStrategy generationStrategy = new ReflectionGenerationStrategy();
            //---------------Assert Precondition----------------
            string propertyName = "PropertyName";
            IModelElement modelElement = new MockModelElement(propertyName);
            //---------------Execute Test ----------------------
            object value = generationStrategy.GetValue(null, modelElement, "Value+");
            //---------------Test Result -----------------------
            Assert.AreEqual("PropertyNames", value);
        }

        [Test]
        public void TestGetValue_PluralAndCamelCase()
        {
            //---------------Set up test pack-------------------
            //<<|=#Property+|>>
            IGenerationStrategy generationStrategy = new ReflectionGenerationStrategy();
            //---------------Assert Precondition----------------
            string propertyName = "PropertyName";
            IModelElement modelElement = new MockModelElement(propertyName);
            //---------------Execute Test ----------------------
            object value = generationStrategy.GetValue(null, modelElement, "#Value+");
            //---------------Test Result -----------------------
            Assert.AreEqual("propertyNames", value);
        }

        [Test, Ignore("Future feature")]
        public void TestGetValue_SubProperties()
        {
            //---------------Set up test pack-------------------
            //<<|=Parent.ParentProperty|>>
            IGenerationStrategy generationStrategy = new ReflectionGenerationStrategy();
            //---------------Assert Precondition----------------
            MockModelElementParent parent = new MockModelElementParent();
            parent.ParentProperty = "hello";

            string propertyName = "PropertyName";
            IModelElement modelElement = new MockModelElement(propertyName);
            modelElement.Parent = parent;
            //---------------Execute Test ----------------------
            object value = generationStrategy.GetValue(null, modelElement, "Parent.ParentProperty");
            //---------------Test Result -----------------------
            Assert.AreEqual("hello", value);
        }

        [Test]
        public void TestGetCollection()
        {
            //---------------Set up test pack-------------------
            IGenerationStrategy generationStrategy = new ReflectionGenerationStrategy();
            //---------------Assert Precondition----------------
            MockModelElement modelElement = new MockModelElement();
            modelElement.ModelElements.Add(new MockModelElement());
            //---------------Execute Test ----------------------
            IEnumerable<IModelElement> list = generationStrategy.GetCollection(null, modelElement, "ModelElements");
            //---------------Test Result -----------------------
            Assert.AreSame(modelElement.ModelElements, list);
        }

        [Test]
        public void TestGetCollection_OfCollection()
        {
            //---------------Set up test pack-------------------
            IGenerationStrategy generationStrategy = new ReflectionGenerationStrategy();
            //---------------Assert Precondition----------------
            MockModelElement modelElement = new MockModelElement();
            modelElement.EnumerableModelElements.Add(new MockModelElement());
            //---------------Execute Test ----------------------
            IEnumerable<IModelElement> list = generationStrategy.GetCollection(null, modelElement, "EnumerableModelElements");
            //---------------Test Result -----------------------
            Assert.AreSame(modelElement.EnumerableModelElements, list);
        }

        [Test]
        public void TestGetCollection_OfSubTypeItems()
        {
            //---------------Set up test pack-------------------
            IGenerationStrategy generationStrategy = new ReflectionGenerationStrategy();
            //---------------Assert Precondition----------------
            MockModelElement modelElement = new MockModelElement();
            modelElement.EnumerableModelClasses.Add(CreateMockModelClass());
            //---------------Execute Test ----------------------
            IEnumerable<IModelElement> list = generationStrategy.GetCollection(null, modelElement, "EnumerableModelClasses");
            //---------------Test Result -----------------------
            Assert.AreEqual(modelElement.EnumerableModelClasses, list);
        }

        [Test]
        public void TestGetCollection_NotEnumerable()
        {
            //---------------Set up test pack-------------------
            IGenerationStrategy generationStrategy = new ReflectionGenerationStrategy();
            //---------------Assert Precondition----------------
            MockModelElement modelElement = new MockModelElement(1);
            //---------------Execute Test ----------------------
            try
            {
                IEnumerable<IModelElement> list = generationStrategy.GetCollection(null, modelElement, "Value");
                //---------------Test Result -----------------------
                Assert.Fail("Should have thrown an error");
            }
            catch (InvalidCastException ex)
            {
                StringAssert.Contains("The property 'Value' did not return an object of type IEnumerable.", ex.Message);
            }
        }

        [Test]
        public void TestGetCollection_EnumerableButItemsNotIModelElement()
        {
            //---------------Set up test pack-------------------
            IGenerationStrategy generationStrategy = new ReflectionGenerationStrategy();
            //---------------Assert Precondition----------------
            IList<object> myObjects = new List<object>() { CreateMockModelClass(), 400, 2300, "x" };
            MockModelElement modelElement = new MockModelElement(myObjects);
            //---------------Execute Test ----------------------
            try
            {
                generationStrategy.GetCollection(null, modelElement, "Value");
                //---------------Test Result -----------------------
                Assert.Fail("Should have thrown an error");
            }
            catch (InvalidCastException ex)
            {
                StringAssert.Contains("The property 'Value' returned an IEnumerable but none of the items were of type IModelElement.", ex.Message);
            }
        }

        [Test]
        public void TestGetCollection_PropertyReturnsNull()
        {
            //---------------Set up test pack-------------------
            IGenerationStrategy generationStrategy = new ReflectionGenerationStrategy();
            //---------------Assert Precondition----------------
            MockModelElement modelElement = new MockModelElement(null);
            //---------------Execute Test ----------------------
            IEnumerable<IModelElement> list = generationStrategy.GetCollection(null, modelElement, "Value");
            //---------------Test Result -----------------------
            Assert.AreEqual(new List<IModelElement>(), list);
        }

        [Test]
        public void TestGetCollection_NonExistantProperty()
        {
            //---------------Set up test pack-------------------
            IGenerationStrategy generationStrategy = new ReflectionGenerationStrategy();
            string collectionName = "NotExistingProp";
            //---------------Assert Precondition----------------
            IModelElement modelElement = new MockModelElement(null);
            //---------------Execute Test ----------------------
            try
            {
                generationStrategy.GetCollection(null, modelElement, collectionName);
                Assert.Fail("Should have thrown an error");
                //---------------Test Result -----------------------
            }
            catch (PropertyMissingException ex)
            {
                StringAssert.Contains(collectionName, ex.PropertyName);
                StringAssert.Contains(string.Format("The property '{0}' does not exist on this IModelElement of type '{1}'.", collectionName, modelElement.GetType().FullName), ex.Message);
            }
        }

        [Test]
        public void TestGetCollection_ParentProperty()
        {
            //---------------Set up test pack-------------------
            IGenerationStrategy generationStrategy = new ReflectionGenerationStrategy();
            string collectionName = "ModelChildren";
            //---------------Assert Precondition----------------
            MockModelElementParent modelElementParent = new MockModelElementParent();
            modelElementParent.ModelChildren = new List<IModelElement>();
            MockModelElement modelElement = new MockModelElement(null);
            modelElement.Parent = modelElementParent;
            ModelStrategyMapper modelStrategyMapper = new ModelStrategyMapper();
            modelStrategyMapper.SetStrategy(typeof(IModelElement), generationStrategy);
            //---------------Execute Test ----------------------
            IEnumerable<IModelElement> value = generationStrategy.GetCollection(modelStrategyMapper, modelElement, collectionName);
            //---------------Test Result -----------------------
            Assert.AreSame(modelElementParent.ModelChildren, value);
        }

        [Test]
        public void TestGetCollection_ParentProperty_DoesntExist()
        {
            //---------------Set up test pack-------------------
            IGenerationStrategy generationStrategy = new ReflectionGenerationStrategy();
            string propertyName = "NonExistingParentModelChildren";
            //---------------Assert Precondition----------------
            MockModelElementParent modelElementParent = new MockModelElementParent();
            modelElementParent.ModelChildren = new List<IModelElement>();
            MockModelElement modelElement = new MockModelElement(null);
            modelElement.Parent = modelElementParent;
            ModelStrategyMapper modelStrategyMapper = new ModelStrategyMapper();
            modelStrategyMapper.SetStrategy(typeof(IModelElement), generationStrategy);
            //---------------Execute Test ----------------------
            try
            {
                generationStrategy.GetCollection(modelStrategyMapper, modelElement, propertyName);
                Assert.Fail("Should have thrown an error");
                //---------------Test Result -----------------------
            }
            catch (PropertyMissingException ex)
            {
                StringAssert.Contains(propertyName, ex.PropertyName);
                StringAssert.Contains(string.Format("The property '{0}' does not exist on this IModelElement of type '{1}'.", propertyName, modelElement.GetType().FullName), ex.Message);
            }
        }

        [Test]
        public void Test_Generation_WithComplexPart_WithParentProperty()
        {
            //---------------Set up test pack-------------------
            //<<|=ParentProperty|>> <<|=ParentProperty|>>;
            //<<|FOREACH(ModelChildren):
            //<<|=ParentProperty|>>.<<|=Value|>> = 1;
            //|>>

            const string BOCLASSNAME = "ParentProperty";
            const string literal1 = " ";
            const string BOVARIABLENAME = "ParentProperty";
            const string literal2 = ";\n";
            const string collectionName = "ModelChildren";
            const string literal3 = ".";
            const string literal4 = " = 1;\n";
            const string PROPNAME = "Value";
            var propValue1 = "Value1";
            var propValue2 = "Value2";
            const string boClassNameValue = "ClassName";

            const string boVariableNameValue = "ClassName";

            ValueExpression valueExpression1 = new ValueExpression(BOCLASSNAME);
            LiteralExpression literalExpression1 = new LiteralExpression(literal1);
            valueExpression1.Next = literalExpression1;

            ValueExpression valueExpression2 = new ValueExpression(BOVARIABLENAME);
            literalExpression1.Next = valueExpression2;

            LiteralExpression literalExpression2 = new LiteralExpression(literal2);
            valueExpression2.Next = literalExpression2;

            ForEachExpression forEachExpression = new ForEachExpression(collectionName);
            {
                ValueExpression valueExpression3 = new ValueExpression(BOVARIABLENAME);
                LiteralExpression literalExpression3 = new LiteralExpression(literal3);
                valueExpression3.Next = literalExpression3;
                ValueExpression valueExpression4 = new ValueExpression(PROPNAME);
                literalExpression3.Next = valueExpression4;
                LiteralExpression literalExpression4 = new LiteralExpression(literal4);
                valueExpression4.Next = literalExpression4;

                forEachExpression.Part = valueExpression3;
            }
            literalExpression2.Next = forEachExpression;

            var strategyStub = new ReflectionGenerationStrategy();
            
            var modelStrategyMapper = new ModelStrategyMapper();
            modelStrategyMapper.SetStrategy(typeof(IModelElement), strategyStub);
            MockModelElementParent modelElementParent = new MockModelElementParent {ParentProperty = boClassNameValue};
            MockModelElement mockModelElement1 = new MockModelElement {Parent = modelElementParent, Value = propValue1};
            modelElementParent.ModelChildren.Add(mockModelElement1);
            MockModelElement mockModelElement2 = new MockModelElement {Parent = modelElementParent, Value = propValue2};
            modelElementParent.ModelChildren.Add(mockModelElement2);

            //---------------Execute Test ----------------------

            string result = valueExpression1.Generate(modelStrategyMapper, modelElementParent);

            //---------------Test Result -----------------------
            Assert.AreEqual(boClassNameValue + literal1 + boVariableNameValue + literal2 +
                                boVariableNameValue + literal3 + propValue1 + literal4 +
                                boVariableNameValue + literal3 + propValue2 + literal4, result);
        }

        [Test]
        public void TestDelegatesCollectionsNotNull()
        {
            //---------------Set up test pack-------------------
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            ReflectionGenerationStrategy generationStrategy = new ReflectionGenerationStrategy();
            //---------------Test Result -----------------------
            Assert.IsNotNull(generationStrategy.ValueDelegates);
            Assert.IsNotNull(generationStrategy.CollectionDelegates);
        }

        [Test]
        public void TestValueDelegates_OveridesReflection()
        {
            //---------------Set up test pack-------------------
            const string returnString = "hello world";
            const string propertyName = "Value";
            ReflectionGenerationStrategy generationStrategy = new ReflectionGenerationStrategy();
            generationStrategy.ValueDelegates.Add(propertyName, delegate { return returnString; });

            IModelElement modelElement = new MockModelElement(propertyName);
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            object value = generationStrategy.GetValue(null, modelElement, propertyName);
            //---------------Test Result -----------------------
            Assert.AreEqual(returnString, value);
        }

        [Test]
        public void TestValueDelegates_CaseInsensitive()
        {
            //---------------Set up test pack-------------------
            const string returnString = "hello world";
            const string propertyName = "Value";
            ReflectionGenerationStrategy generationStrategy = new ReflectionGenerationStrategy();
            generationStrategy.ValueDelegates.Add(propertyName.ToLower(), delegate { return returnString; });

            IModelElement modelElement = new MockModelElement(propertyName);
            //---------------Assert Precondition----------------

            //---------------Execute Test ----------------------
            object value = generationStrategy.GetValue(null, modelElement, propertyName.ToUpper());
            //---------------Test Result -----------------------
            Assert.AreEqual(returnString, value);
        }

        [Test]
        public void TestCollectionDelegates_OveridesReflection()
        {
            //---------------Set up test pack-------------------
            List<IModelElement> expectedList = new List<IModelElement>();

            const string propertyName = "Value";
            ReflectionGenerationStrategy generationStrategy = new ReflectionGenerationStrategy();
            generationStrategy.CollectionDelegates.Add(propertyName, delegate { return expectedList; });

            MockModelElement modelElement = new MockModelElement();
            modelElement.ModelElements.Add(new MockModelElement());
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            IEnumerable<IModelElement> list = generationStrategy.GetCollection(null, modelElement, propertyName);
            //---------------Test Result -----------------------
            Assert.AreSame(expectedList, list);
        }

        [Test]
        public void TestCollectionDelegates_CaseInsensitive()
        {
            //---------------Set up test pack-------------------
            List<IModelElement> expectedList = new List<IModelElement>();

            const string propertyName = "Value";
            ReflectionGenerationStrategy generationStrategy = new ReflectionGenerationStrategy();
            generationStrategy.CollectionDelegates.Add(propertyName.ToLower(), delegate { return expectedList; });

            MockModelElement modelElement = new MockModelElement();
            modelElement.ModelElements.Add(new MockModelElement());
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            IEnumerable<IModelElement> list = generationStrategy.GetCollection(null, modelElement, propertyName.ToUpper());
            //---------------Test Result -----------------------
            Assert.AreSame(expectedList, list);
        }

        [Test]
        public void TestWithExplicitInterfaceImplementation()
        {
            //---------------Set up test pack-------------------
            IModelElement parentStub = new ModelElementWithExplicitInterfaceImplementationStub();
            IModelElement stub = new ModelElementWithExplicitInterfaceImplementationStub();
            stub.Parent = parentStub;


            var strategyStub = new ReflectionGenerationStrategy();
            var modelStrategyMapper = new ModelStrategyMapper();
            modelStrategyMapper.SetStrategy(typeof(IModelElement), strategyStub);
            //---------------Assert PreConditions---------------            
            //---------------Execute Test ----------------------
            object parent = strategyStub.GetReflectedValue(modelStrategyMapper, stub, "Parent");
            //---------------Test Result -----------------------
            Assert.AreSame(parent, parentStub);
            //---------------Tear Down -------------------------          
        }

        [Test]
        public void TestDotInPropertyCallsToSubproperty()
        {
            //---------------Set up test pack-------------------
            MockModelElement stub = new MockModelElement();
            MockModelElementParent parentStub = new MockModelElementParent();
            const string val = "parentpropertyvalue";
            parentStub.ParentProperty = val;
            stub.Parent = parentStub;
            var strategyStub = new ReflectionGenerationStrategy();
            var modelStrategyMapper = new ModelStrategyMapper();
            modelStrategyMapper.SetStrategy(typeof(IModelElement), strategyStub);

            //---------------Assert PreConditions---------------            
            //---------------Execute Test ----------------------
            object parentValue = strategyStub.GetReflectedValue(modelStrategyMapper, stub, "Parent.ParentProperty");
            //---------------Test Result -----------------------
            Assert.AreEqual(val, parentValue);
            //---------------Tear Down -------------------------          
        }
        [Test]
        public void Test_GetReflectedCollection_WhenAllProperties_SuperClass_TwoLevel_ShouldUseSubClassesClassName()
        {
            //---------------Set up test pack-------------------
            DMClass dmClass = new DMClass { ClassNameBO = "SubClass" };
            DMProperty dmPropertySubClass = CreateDmProperty(dmClass);

            DMClass superClass = new DMClass { ClassNameBO = "SuperClass" };
            DMProperty dmPropertySuperClass = CreateDmProperty(superClass);

            DMClass superSuperClass = new DMClass { ClassNameBO = "SuperSuperClass" };
            DMProperty dmPropertySuperSuperClass = CreateDmProperty(superSuperClass);
            superClass.InheritanceSuperClassRelationship = new DMInheritanceRelationship { SuperClass = superSuperClass };

            dmClass.InheritanceSuperClassRelationship = new DMInheritanceRelationship { SuperClass = superClass };
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            ReflectionGenerationStrategy strategy = new ReflectionGenerationStrategy();
            var allProps = strategy.GetReflectedCollection(new ModelStrategyMapper(), dmClass, "AllProperties");
            //---------------Test Result -----------------------
            Assert.IsNotNull(allProps);
            IEnumerable<IModelProperty> allProperties = allProps.Cast<IModelProperty>();
            Assert.IsNotNull(allProperties);
            IModelProperty clonedSubClassProp = allProperties.First(property => property.PropertyName == dmPropertySubClass.PropertyName);
            Assert.AreEqual(dmClass.ClassNameBO, ((IModelClass)clonedSubClassProp.Parent).ClassName);
            IModelProperty clonedSuperClassProp = allProperties.First(property => property.PropertyName == dmPropertySuperClass.PropertyName);
            Assert.AreEqual(dmClass.ClassNameBO, ((IModelClass)clonedSuperClassProp.Parent).ClassName);
            IModelProperty clonedSuperSuperClassProp = allProperties.First(property => property.PropertyName == dmPropertySuperSuperClass.PropertyName);
            Assert.AreEqual(dmClass.ClassNameBO, ((IModelClass)clonedSuperSuperClassProp.Parent).ClassName);
        }

        [Test]
        public void Test_GetReflectedValue_WhenAllProperties_SuperClass_TwoLevel_ShouldUseSubClassesClassName()
        {
            //---------------Set up test pack-------------------
            DMClass dmClass = new DMClass { ClassNameBO = "SubClass" };
            DMProperty dmPropertySubClass = CreateDmProperty(dmClass);

            DMClass superClass = new DMClass { ClassNameBO = "SuperClass" };
            DMProperty dmPropertySuperClass = CreateDmProperty(superClass);

            DMClass superSuperClass = new DMClass { ClassNameBO = "SuperSuperClass" };
            DMProperty dmPropertySuperSuperClass = CreateDmProperty(superSuperClass);
            superClass.InheritanceSuperClassRelationship = new DMInheritanceRelationship { SuperClass = superSuperClass };

            dmClass.InheritanceSuperClassRelationship = new DMInheritanceRelationship { SuperClass = superClass };
            //---------------Assert Precondition----------------
            //---------------Execute Test ----------------------
            ReflectionGenerationStrategy strategy = new ReflectionGenerationStrategy();
            var allProps = strategy.GetReflectedValue(new ModelStrategyMapper(), dmClass, "AllProperties");
            //---------------Test Result -----------------------
            Assert.IsNotNull(allProps);
            AssertValueIsEnumerable("AllProperties", allProps);
            IEnumerable<IModelProperty>  allProperties = GetEnumerableCollection(allProps);
            IModelProperty clonedSubClassProp = allProperties.First(property => property.PropertyName == dmPropertySubClass.PropertyName);
            Assert.AreEqual(dmClass.ClassNameBO, ((IModelClass)clonedSubClassProp.Parent).ClassName);
            IModelProperty clonedSuperClassProp = allProperties.First(property => property.PropertyName == dmPropertySuperClass.PropertyName);
            Assert.AreEqual(dmClass.ClassNameBO, ((IModelClass)clonedSuperClassProp.Parent).ClassName);
            IModelProperty clonedSuperSuperClassProp = allProperties.First(property => property.PropertyName == dmPropertySuperSuperClass.PropertyName);
            Assert.AreEqual(dmClass.ClassNameBO, ((IModelClass)clonedSuperSuperClassProp.Parent).ClassName);
        }
        private static void AssertValueIsEnumerable(string collectionName, object value)
        {
            Assert.True(value is IEnumerable, collectionName + " should be enumerable");
        }
        private static DMProperty CreateDmProperty(DMClass dmClass)
        {
            DMProperty dmProperty = TestUtilsDMProperty.CreateUnsavedValidDMProperty(dmClass);
            return dmProperty;
        }
        private static IEnumerable<IModelProperty> GetEnumerableCollection(object col)
        {
            if (col is IEnumerable<IModelProperty> || col.GetType().IsSubclassOf(typeof(IEnumerable<IModelProperty>)))
                return (IEnumerable<IModelProperty>)col;
            List<IModelProperty> list = new List<IModelProperty>(5);
            foreach (object item in (IEnumerable)col)
            {
                list.Add((IModelProperty)item);
            }
            return list.Where(element => element != null);
        }
        private class ModelElementWithExplicitInterfaceImplementationStub : IModelElement
        {
            private ModelElementWithExplicitInterfaceImplementationStub _parent;
            IModelElement IModelElement.Parent
            {
                get {
                return _parent;
            } set
            {
                _parent = (ModelElementWithExplicitInterfaceImplementationStub) value;  
            } }
        }

        private class MockModelElement : IModelElement
        {
            public object Value { get; internal set; }
            public IModelElement Parent { get; set; }

            public MockModelElement()
            {
                ModelElements = new List<IModelElement>();
                EnumerableModelElements = new Collection<IModelElement>();
                EnumerableModelClasses = new List<IModelClass>();

            }

            public MockModelElement(object value) : this()
            {
                Value = value;
            }

            public IList<IModelElement> ModelElements { get; private set; }
            public Collection<IModelElement> EnumerableModelElements { get; private set; }
            public IList<IModelClass> EnumerableModelClasses { get; private set; }
            

        }

        private class MockModelElementParent : IModelElement
        {
            public object ParentProperty { get; internal set; }
            public IModelElement Parent { get; set; }

            public IList<IModelElement> ModelChildren { get; internal set; }

            public MockModelElementParent()
            {
                ModelChildren = new List<IModelElement>();
            }
        }

        private static IModelClass CreateMockModelClass()
        {
            return MockRepository.GenerateStub<IModelClass>();
        }
    }
}